home *** CD-ROM | disk | FTP | other *** search
- /*
- * Linux interface for packet capture lib ported by Adam Caldwell
- * (acaldwel@ace.cs.ohiou.edu). Based on the pcap-snoop.c file.
- * May be freely redistributed as per the GNU license
- */
- #include <sys/param.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <netdb.h>
- #include <ctype.h>
- #include <signal.h>
- #include <errno.h>
- #include <sys/time.h>
- #include <sys/socket.h>
- #include <sys/file.h>
- #include <sys/ioctl.h>
- #include <malloc.h>
- #include <memory.h>
- #include <unistd.h>
-
-
- #include <net/if.h>
- #include <net/if_arp.h>
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- #include <netinet/udp.h>
- #include <netinet/tcp.h>
- #include <net/bpf.h>
-
- #include "pcap-int.h"
-
- static char snoop_device[255];
- struct ifreq ifr_orig;
-
- void restore_interface(void);
-
- void
- restore_interface()
- {
- int fd;
-
- fd = socket(PF_INET, SOCK_PACKET, htons(0x0003));
- if (fd < 0) {
- printf("Warning: could not restore interface to normal.\n");
- return;
- }
- if (ioctl(fd, SIOCSIFFLAGS, &ifr_orig) < 0)
- printf("Warning: could not restore interface to normal.\n");
- }
-
- int
- pcap_read_live(pcap_t * p, int cnt, pcap_handler callback, u_char * user)
- {
- register int datalen;
- register int caplen;
- struct sockaddr from;
- int from_len=sizeof(from);
- char *buf;
- int bufsize;
-
- if (p->linktype == DLT_SLIP) {
- buf = (char *) p->buffer + 16;
- bufsize = p->bufsize - 16;
- memset(p->buffer, 0, 16);
- #ifdef LINUX_PPP_PATCH
- } else if (p->linktype == DLT_PPP || p->linktype == DLT_NULL) {
- buf = (char *) p->buffer + 4;
- bufsize = p->bufsize - 4;
- p->buffer[0] = 0x00;
- p->buffer[1] = 0x00;
- p->buffer[2] = 0x00; /* hack: force IP protocol */
- p->buffer[3] = 0x21; /* kernel ppp.c should be fixed to
- include protocol field */
- #endif
- } else {
- buf = (char *) p->buffer;
- bufsize = p->bufsize;
- }
-
- /* do until we find something from the right interface */
- do {
- datalen = recvfrom(p->fd, buf, bufsize, 0, &from, &from_len);
-
- if (datalen < 0) {
- switch (errno) {
- case EWOULDBLOCK:
- return 0;
- }
- sprintf(p->errbuf, "read: %s", pcap_strerror(errno));
- return -1;
- }
- } while (strcmp(snoop_device, from.sa_data));
-
- if (p->linktype == DLT_SLIP)
- datalen += 16;
- #ifdef LINUX_PPP_PATCH
- else if (p->linktype == DLT_PPP || p->linktype == DLT_NULL)
- datalen += 4;
- #endif
-
- caplen = (datalen > p->bufsize) ? p->bufsize : datalen;
-
- if (caplen > p->snapshot)
- caplen = p->snapshot;
-
- ++p->md.stat.ps_recv;
-
- if (p->fcode.bf_insns == NULL ||
- bpf_filter(p->fcode.bf_insns, (char *) p->buffer, datalen, caplen)) {
- struct pcap_hdr hdr;
-
- /* use gettimeofday if support for SIOCGSTAMP is missing or
- the request fails (it does in old kernel versions) */
- #ifdef SIOCGSTAMP
- if (ioctl(p->fd, SIOCGSTAMP, &hdr.ts) < 0) /* get the timestamp */
- #endif
- gettimeofday(&hdr.ts, 0);
-
- hdr.len = datalen;
- hdr.caplen = caplen;
- hdr.drops = 0;
- (*callback) (user, &hdr, (char *) p->buffer);
- return 1;
- }
- return 0;
- }
-
- int
- pcap_stats_live(pcap_t * p, struct pcap_stat *ps)
- {
- ps->ps_drop = 0;
- ps->ps_recv = p->md.stat.ps_recv;
- ps->ps_ifdrop = 0;
- return 0;
- }
-
- pcap_t *
- pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
- {
- pcap_t *p;
- struct ifreq ifr;
- int has_promisc=0;
-
- p = (pcap_t *) malloc(sizeof(*p));
- if (p == NULL) {
- strcpy(ebuf, "no swap");
- return 0;
- }
- bzero(p, sizeof(*p));
- if (strncmp("et", device, 2) == 0) {
- p->linktype = DLT_EN10MB;
- has_promisc = 1;
- }
- else if (strncmp("sl", device, 2) == 0)
- p->linktype = DLT_SLIP;
- else if (strncmp("pp", device, 2) == 0)
- p->linktype = DLT_PPP;
- else if (strcmp("lo",device) == 0)
- p->linktype = DLT_EN10MB; /* Why on earth does linux do this? */
- else {
- sprintf(ebuf, "socket: unknown physical layer type");
- goto bad;
- }
- p->fd = -1;
- p->bufsize = 4096;
- p->buffer = (u_char *) malloc(p->bufsize);
- if (p->buffer == NULL) {
- strcpy(ebuf, "no swap");
- goto bad;
- }
- p->fd = socket(PF_INET, SOCK_PACKET, htons(0x0003));
- if (p->fd < 0) {
- sprintf(ebuf, "socket: %s", pcap_strerror(errno));
- goto bad;
- }
- if (has_promisc && promisc) {
- strcpy(ifr.ifr_name, device); /* interface we're gonna use */
- if (ioctl(p->fd, SIOCGIFFLAGS, &ifr) < 0) { /* get flags */
- sprintf(ebuf, "ioctl: %s", pcap_strerror(errno));
- goto bad;
- }
- ifr_orig = ifr;
- atexit(restore_interface);
- ifr.ifr_flags |= IFF_PROMISC; /* set promiscuous mode */
-
- if (ioctl(p->fd, SIOCSIFFLAGS, &ifr) < 0) { /* set flags */
- sprintf(ebuf, "ioctl: %s", pcap_strerror(errno));
- goto bad;
- }
- }
- strcpy(snoop_device, device);
-
- p->snapshot = snaplen;
- return p;
- bad:
- if (p->fd >= 0)
- close(p->fd);
- if (p->buffer != NULL)
- free(p->buffer);
- free(p);
- return 0;
- }
-
- int
- pcap_setfilter_live(pcap_t * p, struct bpf_program *fp)
- {
- p->fcode = *fp;
- return 0;
- }
-